package pers.chao.tool.validate;

import javax.validation.*;
import java.util.Set;

/**
 * Description: Bean(pojo)的字段验证工具，主要依赖JSR303，使用Spring提供的工具
 * <p>
 * 注解      |       功能
 *
 * @AssertFalse 可以为null, 如果不为null的话必须为false
 * @AssertTrue 可以为null, 如果不为null的话必须为true
 * @DecimalMax 设置不能超过最大值
 * @DecimalMin 设置不能超过最小值
 * @Digits 设置必须是数字且数字整数的位数和小数的位数必须在指定范围内
 * @Future 日期必须在当前日期的未来
 * @Past 日期必须在当前日期的过去
 * @Max 最大不得超过此最大值
 * @Min 最大不得小于此最小值
 * @NotNull 不能为null，可以是空
 * @Null 必须为null
 * @Pattern 必须满足指定的正则表达式
 * @Size 集合、数组、map等的size()值必须在指定范围内
 * @Email 必须是email格式
 * @Length 长度必须在指定范围内
 * @NotBlank 字符串不能为null, 字符串trim()后也不能等于“”
 * @NotEmpty 不能为null，集合、数组、map等size()不能为0；字符串trim()后可以等于“”
 * @Range 值必须在指定范围内
 * <p>
 * refer： https://blog.csdn.net/justry_deng/article/details/86571671
 **/
public final class Validations {
	private static final ValidatorFactory validatorFactory = javax.validation.Validation.buildDefaultValidatorFactory();
	private static final Validator validator = validatorFactory.getValidator();

	/**
	 * 验证
	 *
	 * @param obj   被验证对象
	 * @param group 组
	 * @param <T>
	 * @return
	 */
	public static <T> boolean validate(T obj, Class<?>... group) {
		Set<ConstraintViolation<T>> errorMsg = validator.validate(obj, group);
		StringBuilder err = new StringBuilder();
		errorMsg.forEach(cv -> {
			String clazz = cv.getRootBean().getClass().getName(); // 类
			String prop = cv.getPropertyPath().toString(); // 属性
			String msg = cv.getMessage(); // 错误信息
			err.append(String.format("[class: %s, prop: %s, message: %s];", clazz, prop, msg));
		});
		throw new ValidateException("Validating error of bean's properties, {}", err.toString());
	}

	// 组解释: 注解的groups属性指定了组的类时，只有这些组会被检验
	// Example.class组，被检查的属性有被标识了Example和Default的组(无指定组的属性默认为Default)
	// import javax.validation.groups.Default;
//	public interface Example extends Default {
//	}
//
//	public class ExampleBean {
//		@Min(value = 10, groups = Example.class)
//		@Max(20)
//		private Integer number;
//
//		@Valid  // 嵌套其他bean时使用的注解，其他bean也是使用普通的注解
//		private Example example;
//	}

	/**
	 *
	 * @Validated 在Controller中放在类上和参数前的区别:
	 * 1.bean中的字段已经有注解标识
	 * 2.普通字段作验证
	 *
	 * @RequestMapping(value = "/test/one")
	 * public String validatioOne(@Validated ValidationBeanModel.AbcDecimalMax myDecimalMax) {
	 *     System.out.println(myDecimalMax.getMyDecimalMax());
	 *     return "one pass!";
	 * }
	 *
	 *
	 * @RequestMapping(value = "/test/six")
	 * @Validated
	 * public String validatioSix(@DecimalMax(value = "12.3") String myDecimalMax) {
	 *    System.out.println(myDecimalMax);
	 *    return "six pass!";
	 * }
	 */
}
